package com.huawei.cloud.phone.management.domain.connection;

import com.huawei.cloud.phone.management.common.exception.InvalidParamException;
import com.huawei.cloud.phone.management.common.exception.PhoneStatusException;
import com.huawei.cloud.phone.management.common.utils.Constants;
import com.huawei.cloud.phone.management.domain.cache.CacheResource;
import com.huawei.cloud.phone.management.domain.connection.status.ConnectionState;
import com.huawei.cloud.phone.management.domain.connection.status.ConnectionStateFactory;
import com.huawei.cloud.phone.management.domain.phone.Phone;
import com.huawei.cloud.phone.management.domain.phone.PhoneGateway;
import com.huawei.cloud.phone.management.domain.phone.PhoneUseStatus;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@AllArgsConstructor
@Component
public class ConnectionDomainService {
    private final static long CONNECT_INFO_CACHE_TIME = 200;

    private final ConnectionGateway connectionGateway;

    private final PhoneGateway phoneGateway;

    private final CacheResource<String> cacheResource;

    /**
     * 给用户分配一个可用手机，并创建与一个连接
     * 先从连接数据表中查询之前是否已经分配过，已经分配过直接分配原手机；否则从手机列表中找到一个未分配过的运行中的手机进行分配
     *
     * @param userPhoneId 用户手机ID
     * @return 可用连接
     */
    public Optional<Connection> allocateIdleConnection(@NonNull String userPhoneId) {
        Optional<Connection> connection = connectionGateway.getConnection(userPhoneId);
        if (connection.isPresent()) {
            if (Objects.nonNull(connection.get().getPhone())) {
                Phone phone = connection.get().getPhone();
                if (phone.getUseStatus() != PhoneUseStatus.NORMAL) {
                    throw new PhoneStatusException();
                }
                connection.get().refresh();
                connectionGateway.updateConnection(connection.get());
                return connection;
            }
            connectionGateway.deleteConnection(userPhoneId);
        }
        List<Phone> idlePhones = getIdlePhones();
        return allocateIdleConnection(userPhoneId, idlePhones);
    }

    private List<Phone> getIdlePhones() {
        Set<String> usingPhoneIds = connectionGateway.getAllUsingPhones().stream()
                .map(Phone::getPhoneId)
                .collect(Collectors.toSet());
        List<Phone> readyPhones = phoneGateway.getReadyPhones();
        return readyPhones.stream()
                .filter(phone -> !usingPhoneIds.contains(phone.getPhoneId()))
                .collect(Collectors.toList());
    }

    private Optional<Connection> allocateIdleConnection(String userPhoneId, List<Phone> idlePhones) {
        for (Phone idlePhone : idlePhones) {
            Connection newConnection = new Connection(idlePhone, userPhoneId);
            // 多用户可能同时分配到同一台手机，只能有一个用户分配成功
            if (connectionGateway.addConnection(newConnection)) {
                return Optional.of(newConnection);
            }
            // 同一用户并发登录场景处理，分配同一台手机
            Optional<Connection> connection = connectionGateway.getConnection(userPhoneId);
            if (connection.isPresent()) {
                return connection;
            }
        }
        return Optional.empty();
    }

    /**
     * 缓存连接信息
     *
     * @param phoneId   手机ID
     * @param sessionId 连接sessionId
     */
    public void cacheConnectionInfo(String phoneId, String sessionId) {
        cacheResource.cacheData(phoneId, sessionId, CONNECT_INFO_CACHE_TIME);
    }

    /**
     * 清除缓存的连接信息
     *
     * @param phoneId 手机ID
     */
    public void clearConnectionInfo(String phoneId) {
        cacheResource.clearData(phoneId);
    }

    /**
     * 云机事件认证
     *
     * @param phoneId   连接手机Id
     * @param sessionId 连接sessionId
     */
    public void auth(String phoneId, String sessionId) {
        Optional<String> sessionIdCache = cacheResource.getData(phoneId);
        if (!sessionIdCache.isPresent() || !sessionIdCache.get().equals(sessionId)) {
            throw new InvalidParamException(Constants.SESSION_ID, sessionId);
        }
        cacheResource.refreshTimeout(phoneId, CONNECT_INFO_CACHE_TIME);
    }

    /**
     * 清除用户手机的连接信息
     *
     * @param userPhoneIds 用户手机列表
     */
    public void disconnect(List<String> userPhoneIds) {
        for (String userPhoneId : userPhoneIds) {
            Optional<Connection> connection = connectionGateway.getConnection(userPhoneId);
            if (connection.isPresent() && connection.get().isValid()) {
                ConnectionStateFactory.getOptionalState(connection.get().getPhoneId()).ifPresent(ConnectionState::disconnect);
                cacheResource.clearData(connection.get().getPhoneId());
            }
        }
    }
}
